use actix_web::{HttpResponse};
use chrono::{DateTime, Utc};
use serde::{Serialize, Serializer};
use utoipa::ToSchema;
use crate::base::errors::AppError;

pub type FateResult = Result<HttpResponse, AppError>;

/// 通用API响应包装结构体
///
/// 核心作用：
/// 1. 统一所有API接口的返回格式，降低前端解析成本
/// 2. 适配 OpenAPI 文档生成（通过 `utoipa::ToSchema`）
/// 3. 优化序列化逻辑（无数据时自动隐藏 `data` 字段，减少响应体积）
///
/// 泛型说明：
/// - `T`: 实际返回的数据类型，需实现 `serde::Serialize`（确保可序列化为JSON）
/// - 支持任意可序列化类型（如单个结构体、列表、基础类型等）
#[derive(Serialize, ToSchema)]
pub struct ApiResponse<T> {
    /// 业务状态码（与HTTP状态码区分）
    /// - 成功场景：固定为 200（表示业务逻辑执行成功）
    /// - 错误场景：
    ///   - 4xx：客户端错误（如参数无效、权限不足，示例：400）
    ///   - 5xx：服务端错误（如数据库异常、逻辑错误，示例：500）
    /// - 扩展说明：HTTP响应状态码统一为 200，业务错误通过此字段区分
    #[schema(example = 200)]
    pub code: i32,

    /// 业务提示信息
    /// - 成功场景：默认 "操作成功"，可根据业务自定义（如 "数据查询完成"）
    /// - 错误场景：需包含具体错误原因（如 "参数id格式无效"、"数据库连接超时"）
    /// - 设计目的：为前端提供用户友好的提示文案，避免直接返回技术错误栈
    #[schema(example = "操作成功")]
    pub message: String,

    /// 业务数据内容（可选）
    /// - 存在场景：业务成功且需返回数据时（如用户列表、详情信息）
    /// - 缺失场景：业务成功但无数据（如删除操作）、业务错误时
    /// - 序列化规则：通过 `serde(skip_serializing_if = "Option::is_none")` 控制，无数据时不序列化该字段
    /// - 文档标记：`schema(nullable = true)` 适配 OpenAPI 文档的 null 类型声明
    #[serde(skip_serializing_if = "Option::is_none")]
    #[schema(nullable = true)]
    pub data: Option<T>
}

impl ApiResponse<()> {
    pub fn ok() -> HttpResponse {
        let res = ApiResponse {
            code: 200,
            message: "操作成功".to_string(),
            data: Some(())
        };

        HttpResponse::Ok().json(res)
    }

    pub fn error(message: String) -> HttpResponse {
        let res = ApiResponse {
            code: 400,
            message: message,
            data: Some(())
        };

        HttpResponse::Ok().json(res)
    }
}

impl<T> ApiResponse<T>
where
    T: Serialize // ⚠️泛型约束，只有实现了Serialize的类型才能作为ApiResponse<T> 的数据类型
{
    pub fn success(data: T) -> HttpResponse {
        let res = ApiResponse {
            code: 200,
            message: "操作成功".to_string(),
            data: Some(data)
        };

        HttpResponse::Ok().json(res)
    }

    // pub fn error(message: String) -> HttpResponse {
    //     let res: ApiResponse<T> = ApiResponse {
    //         code: 400,
    //         msg: message,
    //         data: None
    //     };

    //     HttpResponse::Ok().json(res)
    // }
}

#[derive(Debug, Serialize, ToSchema)]
pub struct Pagination<T> {
    /// 返回的数据内容
    pub records: Vec<T>,

    /// 当前页
    pub current: i32,

    /// 每页数量
    pub size: i32,

    /// 总数
    pub total: Option<i64>
}

impl <T>Pagination<T> {
    pub fn create(size: i32, current: i32, total: Option<i64>, records: Vec<T>) -> Self {
        Pagination {
            records,
            size,
            current,
            total
        }
    }
}

pub fn format_datetime<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer
{
    let s = dt.format("%Y-%m-%d %H:%M:%S").to_string();
    serializer.serialize_str(&s)
}